import 'reflect-metadata'
import {CONTROLLER, MODULE, PROPERTY, ROUTER_METHOD, ROUTER_PATH} from './constant'
import { PipeTransform } from "./pipe-transform";

export type ModuleMetadata = {
  imports?: Array<Function>
  controllers?: Function[]
}

export interface Type<T = any> extends Function {
  new (...args: any[]): T;
}


export function Controller(path: string) {
  return (target: Object) => {
    Reflect.defineMetadata(CONTROLLER, path, target)
  }
}

export function Injectable() {
  return (target: Object) => {
  }
}

export function Module(metadata: ModuleMetadata) {
  return (target: Object) => {
    Reflect.defineMetadata(MODULE, metadata, target)
  }
}

function createRouterMethod(method: 'get' | 'post') {
  return  (path: string) => {
    return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
      Reflect.defineMetadata(ROUTER_PATH, path, target, propertyKey)
      Reflect.defineMetadata(ROUTER_METHOD, method, target, propertyKey)
    }
  }
}

export const Get = createRouterMethod('get')
export const Post = createRouterMethod('post')

export function createRouteProperty(type: 'query' | 'body') {
  return (Validate?: Type<PipeTransform>) => {
    return (target: Object, method: string, index: number) => {
      const metadata = Reflect.getMetadata(PROPERTY, target, method) || []

      metadata.push({
        type,
        index,
        Validate
      })

      Reflect.defineMetadata(PROPERTY, metadata, target, method)
    }
  }
}

export const Body = createRouteProperty('body')
export const Query = createRouteProperty('query')